package org.finesys.common.log.trace.interceptor.netty;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.finesys.common.log.trace.tracer.Tracer;
import org.finesys.common.log.trace.util.LogstashUtil;
import org.slf4j.MDC;

import static net.logstash.logback.marker.Markers.append;
import static org.finesys.common.log.constants.TraceConstants.*;

@Slf4j
public class NettyGlobalSessionIdInboundHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        // 只处理Http请求
        if (msg instanceof HttpRequest && msg instanceof HttpContent) {
            HttpRequest request = (HttpRequest) msg;
            // 从request header获取链路参数
            HttpHeaders headers = request.headers();
            String traceId = headers.get(TRACE_ID);
            String spanId = headers.get(SPAN_ID);
            String parentId = headers.get(PARENT_ID);
            Tracer.trace(traceId, spanId, parentId);
            // 记录请求开始时间
            MDC.put(START_TIME, String.valueOf(System.currentTimeMillis()));
            log.info(LogstashUtil.customizeMarker(LogstashUtil.kLOG_KEY_TRACE_TAG, NETTY_INVOKE_START), NETTY_INVOKE_START);
        }
        super.channelRead(ctx, msg);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        String start = MDC.get(START_TIME);
        if (StringUtils.isNotBlank(start)) {
            long startTime = Long.parseLong(start);
            long duration = System.currentTimeMillis() - startTime;
            log.info(LogstashUtil.customizeMarker(LogstashUtil.kLOG_KEY_TRACE_TAG, NETTY_INVOKE_OVER)
                            .and(append(LogstashUtil.kLOG_KEY_DURATION, duration)),
                    NETTY_INVOKE_OVER);
            Tracer.remove();
        }
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        Tracer.remove();
        ctx.close();
        super.exceptionCaught(ctx, cause);
    }
}
